package com.ruoyi.robot.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.influxdb.client.InfluxDBClient;
import com.influxdb.client.QueryApi;
import com.influxdb.client.WriteApiBlocking;
import com.influxdb.client.domain.WritePrecision;
import com.influxdb.client.write.Point;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.robot.mapper.RobotTypeMapper;
import com.ruoyi.robot.pojo.po.Robot;
import com.ruoyi.robot.mapper.RobotMapper;
import com.ruoyi.robot.pojo.po.RobotMes;
import com.ruoyi.robot.pojo.po.RobotParameter;
import com.ruoyi.robot.pojo.po.RobotType;
import com.ruoyi.robot.pojo.dto.RobotDto;
import com.ruoyi.robot.service.RobotService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.robot.util.DtoToPoMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.Instant;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author yid
 * @since 2023-01-16
 */
@Service
public class RobotServiceImpl extends ServiceImpl<RobotMapper, Robot> implements RobotService {

    private final InfluxDBClient influxDBClient;
    private final RobotMapper robotMapper;
    private final RobotTypeMapper robotTypeMapper;

    @Autowired
    public RobotServiceImpl(InfluxDBClient influxDBClient, RobotMapper robotMapper, RobotTypeMapper robotTypeMapper) {
        this.influxDBClient = influxDBClient;
        this.robotMapper = robotMapper;
        this.robotTypeMapper = robotTypeMapper;
    }

    /**
     * 查询机器人信息
     *
     * @param productId 机器人信息主键
     * @return 机器人信息
     */
    @Override
    public Robot selectRobotByProductId(Long productId) {
        return robotMapper.selectById(productId);
    }

    /**
     * 查询机器人信息列表
     *
     * @param robotDto 机器人信息
     * @return 机器人信息
     */
    @Override
    public List<Robot> selectRobotList(RobotDto robotDto) {
        Robot robot = DtoToPoMapper.INSTANCE.toRobot(robotDto);
        return robotMapper.selectRobotList(robot);
    }

    /**
     * 新增机器人信息
     *
     * @param robotDto 机器人信息
     * @return 结果
     */
    @Override
    public AjaxResult insertRobot(RobotDto robotDto) {
        Robot robot = DtoToPoMapper.INSTANCE.toRobot(robotDto);
        QueryWrapper<Robot> robotWrapper = new QueryWrapper<>();
        QueryWrapper<RobotType> robotTypeWrapper = new QueryWrapper<>();
        robotWrapper.eq("robot_no",robot.getRobotNo());
        if(robotMapper.selectCount(robotWrapper) != 0){
            return AjaxResult.error("该机器编号已存在");
        }
        robotTypeWrapper.eq("type_id",robot.getTypeId());
        if(robotTypeMapper.selectCount(robotTypeWrapper) == 0){
            return AjaxResult.error("该型号不存在");
        }
        return robotMapper.insert(robot)> 0?AjaxResult.success("新增成功"):AjaxResult.error("新增失败");
    }

    /**
     * 修改机器人信息
     *
     * @param robotDto 机器人信息
     * @return 结果
     */
    @Override
    public int updateRobot(RobotDto robotDto) {
        Robot robot = DtoToPoMapper.INSTANCE.toRobot(robotDto);
        return robotMapper.updateById(robot);
    }

    /**
     * 批量删除机器人信息
     *
     * @param productIds 需要删除的机器人信息主键
     * @return 结果
     */
    @Override
    public int deleteRobotByProductIds(Long[] productIds) {
        return robotMapper.deleteRobotByProductIds(productIds);
    }

    /**
     * 删除机器人信息信息
     *
     * @param productId 机器人信息主键
     * @return 结果
     */
    @Override
    public int deleteRobotByProductId(Long productId) {
        return robotMapper.deleteById(productId);
    }

    /**
     * 新增机器人坐标、清洁度等级
     *
     * @param robotMes 机器人坐标、清洁度等级信息
     * @return 结果
     */
    @Override
    public AjaxResult addCordinates(RobotMes robotMes) {
        WriteApiBlocking writeApi = influxDBClient.getWriteApiBlocking();
        try{
            Point point = Point.measurement("robotMes")
                    .addTag("robotNo",robotMes.getRobotNo())
                    .addField("x", robotMes.getX())
                    .addField("y",robotMes.getY())
                    .addField("z",robotMes.getZ())
                    .addField("cleanRank",robotMes.getCleanRank())
                    .time(Instant.now(), WritePrecision.NS);
            writeApi.writePoint(point);
        }catch (Exception e){
            return AjaxResult.error("插入失败");
        }
        return AjaxResult.success("插入成功");
    }

    /**
     * 查询机器人坐标、清洁度等级
     *
     * @param start 开始时间戳
     * @param end 结束时间戳
     * @return robotMesList 机器人坐标、清洁度等级信息列表
     */
    @Override
    public AjaxResult selectCordinates(String robotNo, Long start, Long end) {
        QueryApi queryApi = influxDBClient.getQueryApi();
        try{
            String sql = "from(bucket: \"%s\")\n ";
            sql +="  |> range(start: %d, stop: %d)\n ";
            sql +="  |> filter(fn: (r) => r._measurement == \"%s\")\n ";
            sql +="  |> filter(fn: (r) => r.robotNo == \"%s\")\n";
            sql +="  |> pivot(\n" +
                    "    rowKey:[\"_time\"],\n" +
                    "    columnKey: [\"_field\"],\n" +
                    "    valueColumn: \"_value\"\n" +
                    "  )";
            String flux = String.format(sql, "xiaopa",start,end,"robotMes",robotNo);
            List<RobotMes> robotMesList = queryApi.query(flux,"xiaopa",RobotMes.class);
            if(robotMesList.size()==0){
                return AjaxResult.success("该时间段数据为空");
            }
            for (RobotMes robotMes:robotMesList) {
                //增加8个小时，使返回时间为北京时间
                robotMes.setTime(robotMes.getTime().plusMillis(TimeUnit.HOURS.toMillis(8)));
            }
            return AjaxResult.success(robotMesList);
        }catch (Exception e){
            return AjaxResult.error("查询失败");
        }
    }

    @Override
    public AjaxResult addRobotParameter(RobotParameter robotParameter) {
        WriteApiBlocking writeApi = influxDBClient.getWriteApiBlocking();
        Point point = Point.measurement("robotParameter")
                .addTag("robotNo",robotParameter.getRobotNo())
                .addField("loadVoltage",robotParameter.getLoadVoltage())
                .addField("velocity",robotParameter.getVelocity())
                .addField("usedTime",robotParameter.getUsedTime())
                .addField("area",robotParameter.getArea())
                .addField("targetNum",robotParameter.getTargetNum())
                .addField("robotTemperature",robotParameter.getRobotTemperature())
                .addField("rollAngle",robotParameter.getRollAngle())
                .addField("pitchAngle",robotParameter.getPitchAngle())
                .addField("courseAngle",robotParameter.getCourseAngle())
                .addField("detection",robotParameter.getDetection())
                .addField("x", robotParameter.getX())
                .addField("y",robotParameter.getY())
                .addField("z",robotParameter.getZ())
                .time(Instant.now(), WritePrecision.NS);
        writeApi.writePoint(point);
        return AjaxResult.success("插入成功");
    }

    @Override
    public AjaxResult selectRobotParameter(String robotNo, Long start, Long end) {
        QueryApi queryApi = influxDBClient.getQueryApi();
        String sql = "from(bucket: \"%s\")\n ";
        sql +="  |> range(start: %d, stop: %d)\n ";
        sql +="  |> filter(fn: (r) => r._measurement == \"%s\")\n ";
        sql +="  |> filter(fn: (r) => r.robotNo == \"%s\")\n";
        sql +="  |> pivot(\n" +
                "    rowKey:[\"_time\"],\n" +
                "    columnKey: [\"_field\"],\n" +
                "    valueColumn: \"_value\"\n" +
                "  )";
        String flux = String.format(sql, "xiaopa",start,end,"robotParameter",robotNo);
        System.out.println(flux);
        List<RobotParameter> robotParameters = queryApi.query(flux,"xiaopa",RobotParameter.class);
        if(robotParameters.size()==0){
            return AjaxResult.success("该时间段数据为空");
        }
        for (RobotParameter robotParameter:robotParameters) {
            //增加8个小时，使返回时间为北京时间
            robotParameter.setTime(robotParameter.getTime().plusMillis(TimeUnit.HOURS.toMillis(8)));
        }
        return AjaxResult.success(robotParameters);
    }
}
